package com.yanqu.road.server.gameplayer.module.activity.foxcard;

import com.yanqu.road.dao.impl.player.UserFoxCardDaoImpl;
import com.yanqu.road.dao.impl.player.UserFoxCardGameDaoImpl;
import com.yanqu.road.dao.impl.player.UserFoxCardMonsterDaoImpl;
import com.yanqu.road.dao.impl.player.UserFoxCardShopDaoImpl;
import com.yanqu.road.entity.activity.ActivityConfig;
import com.yanqu.road.entity.activity.foxcard.*;
import com.yanqu.road.entity.activity.foxcard.config.*;
import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.enums.eLogMoneyType;
import com.yanqu.road.entity.enums.ePlayerAttrType;
import com.yanqu.road.entity.enums.eSystemId;
import com.yanqu.road.entity.log.foxcard.*;
import com.yanqu.road.logic.activity.foxcard.FoxCardConfig;
import com.yanqu.road.logic.activity.foxcard.game.FoxCardCombo;
import com.yanqu.road.logic.activity.foxcard.game.FoxCardGameLogic;
import com.yanqu.road.logic.activity.foxcard.game.eFoxCardType;
import com.yanqu.road.logic.helper.CalcPowerResult;
import com.yanqu.road.logic.helper.PowerHelper;
import com.yanqu.road.logic.pb.FoxCardPb;
import com.yanqu.road.pb.activity.FoxCardProto;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.player.AttributeModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.gameplayer.module.useract.UserActModule;
import com.yanqu.road.server.manger.activity.ActivityMgr;
import com.yanqu.road.server.manger.activity.foxcard.FoxCardMgr;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.manger.log.AutoLogMgr;
import com.yanqu.road.server.protocol.ClientProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigDecimal;
import java.util.*;

public class FoxCardModule extends GeneralModule {
    public FoxCardModule(GamePlayer player) {
        super(player);
    }

    private UserFoxCardData userData;
    private UserFoxCardGameData userGameData;

    @Override
    public boolean loadData() {
        FoxCardConfig config = FoxCardMgr.getConfig();
        if (config == null) {
            return true;
        }
        userData = new UserFoxCardDaoImpl().getUserFoxCardData(config.getActivityId(), getUserId());
        userGameData = new UserFoxCardGameDaoImpl().getUserFoxCardGameData(config.getActivityId(), getUserId());
        if (userGameData != null) {
            UserFoxCardShop userFoxCardShop = new UserFoxCardShopDaoImpl().getUserFoxCardShop(config.getActivityId(), getUserId());
            userGameData.setShop(userFoxCardShop);

            Map<Integer, UserFoxCardMonster> monsterMap = new UserFoxCardMonsterDaoImpl().getUserFoxCardMonster(config.getActivityId(), getUserId());
            userGameData.setMonsterMap(monsterMap);
        }

        return true;
    }

    @Override
    public boolean afterLoadData() {
        return true;
    }

    @Override
    public boolean saveData() {
        if (userData != null) {
            if (userData.isInsertOption()) {
                new UserFoxCardDaoImpl().add(userData);
            } else if (userData.isUpdateOption()) {
                new UserFoxCardDaoImpl().update(userData);
            }
        }

        if (userGameData != null) {
            if (userGameData.isInsertOption()) {
                new UserFoxCardGameDaoImpl().add(userGameData);
            } else if (userGameData.isUpdateOption()) {
                new UserFoxCardGameDaoImpl().update(userGameData);
            }

            if (userGameData.getShop() != null) {
                if (userGameData.getShop().isInsertOption()) {
                    new UserFoxCardShopDaoImpl().add(userGameData.getShop());
                } else if (userGameData.getShop().isUpdateOption()) {
                    new UserFoxCardShopDaoImpl().update(userGameData.getShop());
                }

                for (UserFoxCardMonster monster : userGameData.getMonsterMap().values()) {
                    if (monster.isInsertOption()) {
                        new UserFoxCardMonsterDaoImpl().add(monster);
                    } else if (monster.isUpdateOption()) {
                        new UserFoxCardMonsterDaoImpl().update(monster);
                    }
                }
            }
        }

        return true;
    }

    @Override
    public void afterLogin() {
        initSystemOpen();
        resetOneDay(true);
    }

    private void syncUserData() {
        if (userData == null || userGameData == null) {
            return;
        }

        FoxCardConfig config = FoxCardMgr.getConfig();
        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return;
        }

        FoxCardProto.FoxCardUserDataSyncMsg.Builder syncMsg = FoxCardPb.parseUserSyncMsg(userData, userGameData);
        calcNextPowerTime();
        syncMsg.setPowerRecoverTime(userData.getPowerRecoverTime());
        syncMsg.setPower(getNowPower());
        player.sendPacket(ClientProtocol.U_FOXCARD_USER_DATA_SYNC, syncMsg);
    }

    private void syncConfig() {
        FoxCardConfig config = FoxCardMgr.getConfig();
        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return;
        }

        if (userData == null) {
            return;
        }

        FoxCardProto.FoxCardConfigSyncMsg.Builder configMsg = FoxCardMgr.getConfigMsg(player.getLanguage());
        player.sendPacket(ClientProtocol.U_FOXCARD_CONFIG_SYNC, configMsg);
    }

    private void initUserData() {
        if (!isSystemOpen()) {
            return;
        }
        FoxCardConfig config = FoxCardMgr.getConfig();
        if (config == null) {
            return;
        }
        if (!ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return;
        }

        synchronized (this) {
            if (userData == null || userData.getActivityId() != config.getActivityId()) {
                userData = new UserFoxCardData(config.getActivityId(), getUserId());
                List<Integer> initEffectCardIds = config.getInitEffectCardIds();
                userData.setUnlockCards(new HashSet<>(initEffectCardIds));
                userData.setGuaranteeAmount(config.getInitGuaranteeNum());
                player.notifyListener(eGamePlayerEventType.FoxCardOneCardUnlock.getValue());
            }

            if (userGameData == null || userGameData.getActivityId() != config.getActivityId()) {
                userGameData = new UserFoxCardGameData(config.getActivityId(), getUserId());
            }
        }
    }

    public boolean isSystemOpen() {
        return SystemOpenMgr.systemOpen(player, eSystemId.FoxCard.getValue());
    }

    public void initSystemOpen() {
        if (!isSystemOpen()) {
            return;
        }
        initUserData();
        syncConfig();
        syncUserData();
    }

    public int checkInShowTime(int activityId) {
        int ret = FoxCardMgr.checkInShowTime(activityId);
        if (ret != 0) {
            return ret;
        }
        if (userData == null || userData.getActivityId() != activityId) {
            return GameErrorCode.E_SYSTEM_NO_OPEN;
        }
        return 0;
    }

    public int checkInTime(int activityId) {
        int ret = FoxCardMgr.checkInTime(activityId);
        if (ret != 0) {
            return ret;
        }
        if (userData == null || userData.getActivityId() != activityId) {
            return GameErrorCode.E_SYSTEM_NO_OPEN;
        }
        return 0;
    }

    public long calcNextPowerTime() {
        if (userData == null) {
            return -1;
        }
        FoxCardConfig config = FoxCardMgr.getConfig();
        if (config == null) {
            return -1;
        }

        if (userData.getPower() >= config.getTreeInitPower()) {
            return 0;
        }

        long powerRecoverCD = config.getPowerRecoverCD(); // 恢复一点体力的时间秒
        long powerRecoverTime = userData.getPowerRecoverTime() / 1000; // 上次恢复体力的时间 秒

        CalcPowerResult calcPowerResult = PowerHelper.calcPower(powerRecoverTime, powerRecoverCD, 1, config.getTreeInitPower(), userData.getPower());
        userData.setPower(calcPowerResult.getCurPower());
        userData.setPowerRecoverTime(calcPowerResult.getLastRecoverTime() * 1000);

        return userData.getPowerRecoverTime() + powerRecoverCD * 1000;
    }

    public int getNowPower() {
        long ret = calcNextPowerTime();
        if (ret == -1) {
            return 0;
        }
        return userData.getPower();
    }

    public void addPower(int power) {
        long ret = calcNextPowerTime();
        if (ret == -1) {
            return;
        }
        userData.setPower(userData.getPower() + power);
        syncUserData();
    }

    public void usePower(int power) {
        long ret = calcNextPowerTime();
        if (ret == -1) {
            return;
        }
        FoxCardConfig config = FoxCardMgr.getConfig();
        int maxPower = config.getTreeInitPower();
        int oldPower = userData.getPower();
        userData.setPower(userData.getPower() - power);
        if (oldPower >= maxPower && userData.getPower() < maxPower) {
            userData.setPowerRecoverTime(DateHelper.getCurrentTime());
        }

        userData.setPowerAmount(userData.getPowerAmount() + power);
    }

    public int treeLottery(FoxCardProto.FoxCardTreeLotteryReqMsg reqMsg) {
        int ret = checkInTime(reqMsg.getActivityId());
        if (ret != 0) {
            return ret;
        }

        FoxCardConfig config = FoxCardMgr.getConfig();
        if (!config.checkPointCanContinueLottery(userData.getTreeCards())) {
            return GameErrorCode.E_FOXCARD_LOTTERY_POINT_NOT_CONTINUE;
        }

        FoxCardTreeLevelConfig treeLevelConfig = config.getTreeLevelConfig(userData.getTreeLevel());
        if (treeLevelConfig == null) {
            return GameErrorCode.E_FOXCARD_LOTTERY_CONFIG_ERR;
        }
        if (reqMsg.hasAutoLottery()) {//有设置自动抽奖
            if (!config.checkAutoLotteryEndPoint(reqMsg.getAutoLottery().getEndAmountPoints())) {
                return GameErrorCode.E_FOXCARD_AUTO_LOTTERY_END_POINT_ERR;
            }
        }

        int oldLevel = userData.getTreeLevel();
        int newLevel = config.calcTreeLevel(userData.getTreeExp());
        if (oldLevel != newLevel) {//可以升级,要先去升级
            return GameErrorCode.E_FOXCARD_TREE_NEED_LV_UP;
        }

        int nowPower = getNowPower();
        if (nowPower < treeLevelConfig.getRollConsume()) {
            return GameErrorCode.E_FOXCARD_LOTTERY_POWER_NOT_ENOUGH;
        }

        if (userData.getTreeCards().isEmpty()) {
            if (userData.getGuaranteeAmount() == -1) {
                return GameErrorCode.E_FOXCARD_TREE_NEED_RANDOM_NEXT_GUARANTEE_NUM;
            }
            userData.setLotteryRound(userData.getLotteryRound() + 1);
            //本轮首抽,如果保底,获得保底组合
            if (userData.getGuaranteePoints().isEmpty()) {
                if (userData.getGuaranteeAmount() == 0 && config.getInitGuaranteeNum() > 0) {
                    List<Integer> points = config.randomOnceTreeGuaranteeList();
                    userData.setGuaranteePoints(points);
                }
            }
        }

        if (reqMsg.hasAutoLottery()) {//有设置自动抽奖
            ArrayList<FoxTreeCard> newTreeCards = new ArrayList<>(userData.getTreeCards());
            for (int i = 0; i < 20; i++) {//最多抽6次
                FoxTreeCard treeCard = config.autoLotteryTreeCard(newTreeCards, userData.getGuaranteeAmount(), reqMsg.getAutoLottery().getEndAmountPoints(), userData.getPowerAmount(),
                        userData.getLotteryRound(), userData.getUnlockCards(), userData.getGuaranteePoints());
                if (treeCard == null) {
                    break;
                }
                usePower(treeLevelConfig.getRollConsume());
                newTreeCards.add(treeCard);

                int totalPoint = config.calcTreeCardsPoint(newTreeCards);

                AutoLogMgr.add(new LogFoxCardLottery(userData.getActivityId(), userData.getUserId(), treeLevelConfig.getRollConsume(), getNowPower(),userData.getTreeLevel(), userData.getPowerAmount(),
                        userData.getLotteryRound(), newTreeCards.size(), treeCard.getCardId(), treeCard.getPoint(), totalPoint));

                nowPower = getNowPower();
                if (nowPower < treeLevelConfig.getRollConsume()) {
                    break;
                }

                newLevel = config.calcTreeLevel(userData.getTreeExp());
                if (oldLevel != newLevel) {//可以升级,要先去升级
                    break;
                }
            }
            userData.setTreeCards(newTreeCards);
        } else {
            FoxTreeCard treeCard = config.randomOnceLotteryCard(userData.getTreeCards(), userData.getGuaranteeAmount(),
                    userData.getPowerAmount(), userData.getLotteryRound(), userData.getUnlockCards(), userData.getGuaranteePoints());
            if (treeCard == null) {
                return GameErrorCode.E_ERROR_DATA;
            }
            usePower(treeLevelConfig.getRollConsume());
            ArrayList<FoxTreeCard> newTreeCards = new ArrayList<>(userData.getTreeCards());
            newTreeCards.add(treeCard);
            userData.setTreeCards(newTreeCards);

            AutoLogMgr.add(new LogFoxCardLottery(userData.getActivityId(), userData.getUserId(), treeLevelConfig.getRollConsume(), getNowPower(), userData.getTreeLevel(), userData.getTreeExp(),
                    userData.getLotteryRound(), newTreeCards.size(), treeCard.getCardId(), treeCard.getPoint(), config.calcTreeCardsPoint(newTreeCards)));
        }

        List<FoxTreeCard> treeCardsHave = new ArrayList<>(userData.getTreeCards());

        FoxCardProto.FoxCardTreeLotteryRespMsg.Builder respMsg = FoxCardProto.FoxCardTreeLotteryRespMsg.newBuilder();
        respMsg.setRet(0);

        FoxCardLotterySettleConfig settleConfig = config.calcLotterySettleConfigBuyTotalPoint(userData.getTreeCards());
        if (settleConfig.getRollType() != 0) {//可以结算的状态
            int totalPoint = config.calcTreeCardsPoint(treeCardsHave);
            List<FoxTreeCard> resultList = new ArrayList<>();
            Integer chooseType = settleConfig.getRewards().get(0);
            int chooseNum = settleConfig.getRewards().get(1);
            boolean isNeedSettle = false;
            if (chooseType == 0) {
                isNeedSettle = true;
            } else if (chooseType == 1 && (userData.getLotteryRound() < config.getUnlockGuaranteeNum() || userData.getUnlockCards().size() >= config.getEffectCardConfigMap().size())) {//随机获得
                if (reqMsg.hasAutoLottery() && reqMsg.getAutoLottery().getIsAutoChose()) {
                    resultList = RandomHelper.getRandomList(treeCardsHave, chooseNum);
                    isNeedSettle = true;
                }
            } else {//手动选择
                if (reqMsg.hasAutoLottery() && reqMsg.getAutoLottery().getIsAutoChose()) {//玩家设置了自动代替手动选择
                    if (reqMsg.getAutoLottery().getIsAutoChoseNotUnlock()) {//是否自动选择未解锁过的,如果都解锁自动选点数大的
                        //排序一下
                        treeCardsHave.sort((o1, o2) -> {
                            boolean isUnlock1 = userData.getUnlockCards().contains(o1.getCardId());
                            boolean isUnlock2 = userData.getUnlockCards().contains(o2.getCardId());
                            int compare = Boolean.compare(isUnlock1, isUnlock2);
                            if (compare == 0) {
                                int quality1 = config.getEffectCardConfigMap().get(o1.getCardId()).getQuality();
                                int quality2 = config.getEffectCardConfigMap().get(o2.getCardId()).getQuality();
                                compare = Integer.compare(quality2, quality1);
                            }
                            if (compare == 0) {
                                compare = Integer.compare(o2.getPoint(), o1.getPoint());
                            }
                            return compare;
                        });
                    } else {
                        Collections.shuffle(treeCardsHave);
                    }

                    for (int i = 0; i < chooseNum; i++) {
                        if (i >= treeCardsHave.size()) {
                            break;
                        }
                        resultList.add(treeCardsHave.get(i));
                    }

                    isNeedSettle = true;
                }
            }

            //结算获得的卡片
            if (isNeedSettle) {
                FoxTreeLotteryResult lotteryResult = settleTreeCards(resultList, settleConfig, totalPoint, treeCardsHave);
                respMsg.addAllAutoChoseCards(lotteryResult.getChooseCards());
                respMsg.addAllUnlockCards(lotteryResult.getUnlockCardIds());
                respMsg.setAddScore(lotteryResult.getScoreAdd());
                respMsg.setReward(lotteryResult.getReward().toHelperString());
            }
        }
        respMsg.addAllTreeCards(FoxCardPb.parseTreeCardTempList(treeCardsHave));

        player.sendPacket(ClientProtocol.U_FOXCARD_TREE_LOTTERY, respMsg);
        syncUserData();
        return 0;
    }

    /**
     * 结算获得的卡片
     *
     * @param treeCards     获得的卡片
     * @param settleConfig  总点数对应的结算配置
     * @param totalPoint    解签中的所有卡片总点数
     * @param treeCardsHave
     */
    private FoxTreeLotteryResult settleTreeCards(List<FoxTreeCard> treeCards, FoxCardLotterySettleConfig settleConfig, int totalPoint, List<FoxTreeCard> treeCardsHave) {
        FoxCardConfig config = FoxCardMgr.getConfig();

        List<FoxCardProto.FoxCardTreeCardTemp> list = new ArrayList<>();
        int treeScoreAdd = 0;
        Set<Integer> unlockCards = new HashSet<>(userData.getUnlockCards());
        List<Integer> unlockNewCards = new ArrayList<>(); //新解锁的卡片
        List<Integer> cardIdChoose = new ArrayList<>();
        for (FoxTreeCard treeCard : treeCardsHave) {
            int score = config.getLotteryConfig(treeCard.getLotteryId()).getScore();
            treeScoreAdd += score;
        }
        for (FoxTreeCard treeCard : treeCards) {

            cardIdChoose.add(treeCard.getCardId());

            if (!unlockCards.contains(treeCard.getCardId())) {
                unlockNewCards.add(treeCard.getCardId());
            }

            unlockCards.add(treeCard.getCardId());

            FoxCardProto.FoxCardTreeCardTemp.Builder builder = FoxCardProto.FoxCardTreeCardTemp.newBuilder();
            builder.setCardId(treeCard.getCardId());
            builder.setLotteryId(treeCard.getLotteryId());
            builder.setPoint(treeCard.getPoint());
//            builder.setScoreAdd(treeCard.getAddScore());
            list.add(builder.build());
        }
        /**
         * 【本轮抽卡点数 * 对应点数的倍率】  调整为 -->
         * 【本轮抽到的卡牌积分总和 * 对应点数的倍率 * 体力倍率】调整为 -->
         * 【本轮抽到的卡牌积分总和 * 对应点数的倍率 * 体力倍率 * 金色保底倍率】
         */
        FoxCardTreeLevelConfig treeLevelConfig = config.getTreeLevelConfig(userData.getTreeLevel());
        int multi = settleConfig.getRewards().get(2); //积分倍率 千分比
        int goldenMulti = 1000;
        if (userData.getGuaranteeAmount() == 0 && userData.isGoldenGuarantee()) {//金色保底
            goldenMulti = config.getGoldenRecallParams().get(1);
        }

        BigDecimal levelMulti = BigDecimal.ONE;
        Map<String, ActivityConfig> configMap = ActivityMgr.getActivityConfigMap(config.getActivityId());
        ActivityConfig scoreMultiConfig = configMap.get("LEVEL_SCORE_PARAM");//代码更新后,才说要加这种配置,只能这么写
        if (scoreMultiConfig != null) {
            List<Integer> levelMultiList = StringUtils.stringToIntegerList(scoreMultiConfig.getValue(), "\\|");
            if (treeLevelConfig.getLevel() <= levelMultiList.size() && levelMultiList.size() > 0) {
                levelMulti = BigDecimal.valueOf(levelMultiList.get(treeLevelConfig.getLevel() - 1)).divide(BigDecimal.valueOf(1000));
            }
        }

        int score = BigDecimal.valueOf(treeScoreAdd).multiply(BigDecimal.valueOf(multi).divide(BigDecimal.valueOf(1000))).
                multiply(BigDecimal.valueOf(goldenMulti).divide(BigDecimal.valueOf(1000))).
                multiply(BigDecimal.valueOf(treeLevelConfig.getRollConsume())).
                multiply(levelMulti).intValue();
        treeScoreAdd = score;

        userData.setUnlockCards(unlockCards);
        userData.setTreeScore(userData.getTreeScore() + treeScoreAdd);
        Property reward = new Property(config.getScoreItemId(), treeScoreAdd);
        Property exReward = new Property();
        if (totalPoint == config.getExRewardPoint()) {
            exReward = PropertyHelper.randomPropertyByListList(treeLevelConfig.getBigRewardList());
            if (userData.getGuaranteeAmount() == 0 && userData.isGoldenGuarantee()) {//金色保底,道具也翻倍
                exReward.goodMulti(BigDecimal.valueOf(config.getGoldenRecallParams().get(1)).divide(BigDecimal.valueOf(1000), 3, BigDecimal.ROUND_UP));
            }
            reward.addProperty(exReward);
        }

        player.getModule(CurrencyModule.class).addCurrency(reward, eLogMoneyType.FoxCard, eLogMoneyType.FoxCardLotteryReward);

        //清空当前姻缘签,更新保底次数
        userData.setTreeCards(new ArrayList<>());
        userData.setGuaranteePoints(new ArrayList<>());
        if (userData.getGuaranteeAmount() >= 0) {
            userData.setGuaranteeAmount(userData.getGuaranteeAmount() - 1);
        }

        player.notifyListener(eGamePlayerEventType.FoxCardTreeScoreRank.getValue());
        player.notifyListener(eGamePlayerEventType.FoxCardTreeScore.getValue());
        player.notifyListener(eGamePlayerEventType.FoxCardUnlockCard.getValue());

        if (!unlockNewCards.isEmpty()) {
            player.notifyListener(eGamePlayerEventType.FoxCardOneCardUnlock.getValue());
        }

        AutoLogMgr.add(new LogFoxCardLotterySettle(userData.getActivityId(), userData.getUserId(), userData.getLotteryRound(), totalPoint, cardIdChoose, treeScoreAdd, userData.getTreeScore()));

        FoxTreeLotteryResult result = new FoxTreeLotteryResult();
        result.setChooseCards(list);
        result.setUnlockCardIds(unlockNewCards);
        result.setScoreAdd(treeScoreAdd);
        result.setReward(exReward);

        return result;
    }

    public int treeLotteryEnd(FoxCardProto.FoxCardTreeLotteryEndReqMsg reqMsg) {
        int ret = checkInTime(reqMsg.getActivityId());
        if (ret != 0) {
            return ret;
        }

        FoxCardConfig config = FoxCardMgr.getConfig();

        FoxCardLotterySettleConfig lotterySettleConfig = config.calcLotterySettleConfigBuyTotalPoint(userData.getTreeCards());
        if (lotterySettleConfig == null) {
            return GameErrorCode.E_FOXCARD_LOTTERY_CONFIG_ERR;
        }

        int chooseType = lotterySettleConfig.getRewards().get(0);
        int chooseNum = lotterySettleConfig.getRewards().get(1);
        if (reqMsg.getTakeNumsCount() != chooseNum) {
            return GameErrorCode.E_FOXCARD_LOTTERY_END_CHOOSE_NUM_ERR;
        }
        List<FoxTreeCard> cardsHave = new ArrayList<>(userData.getTreeCards());
        List<FoxTreeCard> resultList = new ArrayList<>();
        if (chooseType == 1) {//随机
            Collections.shuffle(cardsHave);
            if (userData.getLotteryRound() >= config.getUnlockGuaranteeNum() && userData.getUnlockCards().size() < config.getEffectCardConfigMap().size()) {
                int takeNum = reqMsg.getTakeNums(0);
                if (takeNum < 1 || takeNum > cardsHave.size()) {
                    return GameErrorCode.E_FOXCARD_LOTTERY_END_CHOOSE_NUM_ERR;
                }
                //要把解锁的放到选的位置
                FoxTreeCard[] reSortCards = new FoxTreeCard[cardsHave.size()];
                for (int i = 0; i < cardsHave.size(); i++) {
                    FoxTreeCard treeCard = cardsHave.get(i);
                    if (!userData.getUnlockCards().contains(treeCard.getCardId())) {
                        reSortCards[takeNum - 1] = treeCard;
                        cardsHave.remove(i);
                        break;
                    }
                }

                int idx = 0;
                for (int i = 0; i < reSortCards.length; i++) {
                    if (reSortCards[i] == null) {
                        reSortCards[i] = cardsHave.get(idx++);
                    }
                }

                cardsHave = Arrays.asList(reSortCards);
            }
        }

        Set<Integer> repeatCheck = new HashSet<>();
        for (Integer idx : reqMsg.getTakeNumsList()) {//1开始
            if (idx < 1 || idx > cardsHave.size()) {
                return GameErrorCode.E_FOXCARD_LOTTERY_END_CHOOSE_NUM_ERR;
            }
            if (repeatCheck.contains(idx)) {
                return GameErrorCode.E_FOXCARD_LOTTERY_END_REPEAT_CHOOSE;
            }
            repeatCheck.add(idx);
            resultList.add(cardsHave.get(idx - 1));
        }

        //结算获得的卡片
        FoxTreeLotteryResult lotteryResult = settleTreeCards(resultList, lotterySettleConfig, config.calcTreeCardsPoint(cardsHave), cardsHave);

        FoxCardProto.FoxCardTreeLotteryEndRespMsg.Builder respMsg = FoxCardProto.FoxCardTreeLotteryEndRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.addAllTakeNums(reqMsg.getTakeNumsList());
        respMsg.addAllChooseCards(FoxCardPb.parseTreeCardTempList(cardsHave));
        respMsg.addAllUnlockCards(lotteryResult.getUnlockCardIds());
        respMsg.setAddScore(lotteryResult.getScoreAdd());
        respMsg.setReward(lotteryResult.getReward().toHelperString());
        player.sendPacket(ClientProtocol.U_FOXCARD_TREE_LOTTERY_END, respMsg);

        syncUserData();
        return 0;
    }

    public int equipCard(FoxCardProto.FoxCardEquipCardReqMsg reqMsg) {
        int ret = checkInTime(reqMsg.getActivityId());
        if (ret != 0) {
            return ret;
        }

        FoxCardConfig config = FoxCardMgr.getConfig();

        Set<Integer> repeatCheck = new HashSet<>();
        for (Integer cardId : reqMsg.getEquipCardsList()) {
            if (!userData.getUnlockCards().contains(cardId)) {
                return GameErrorCode.E_FOXCARD_CARD_NOT_UNLOCK;
            }
            if (repeatCheck.contains(cardId)) {
                return GameErrorCode.E_FOXCARD_CARD_ID_REPEAT;
            }
            repeatCheck.add(cardId);
        }

        FoxCardTreeLevelConfig treeLevelConfig = config.getTreeLevelConfig(userData.getTreeLevel());
        if (treeLevelConfig == null) {
            return GameErrorCode.E_FOXCARD_LOTTERY_CONFIG_ERR;
        }

        if (reqMsg.getEquipCardsList().size() > treeLevelConfig.getNum()) {
            return GameErrorCode.E_FOXCARD_EQUIP_NUM_ERR;
        }

        userData.setEquipCards(new ArrayList<>(reqMsg.getEquipCardsList()));

        FoxCardProto.FoxCardEquipCardRespMsg.Builder respMsg = FoxCardProto.FoxCardEquipCardRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.addAllEquipCards(userData.getEquipCards());
        player.sendPacket(ClientProtocol.U_FOXCARD_EQUIP_CARD, respMsg);
        return 0;
    }

    public int enterStage(FoxCardProto.FoxCardEnterStageReqMsg reqMsg) {
        int ret = checkInTime(reqMsg.getActivityId());
        if (ret != 0) {
            return ret;
        }

        FoxCardConfig config = FoxCardMgr.getConfig();

        FoxCardTreeLevelConfig treeLevelConfig = config.getTreeLevelConfig(userData.getTreeLevel());
        if (treeLevelConfig == null) {
            return GameErrorCode.E_FOXCARD_LOTTERY_CONFIG_ERR;
        }

        FoxCardChapterConfig chapterConfig = config.getChapterConfigMap().get(reqMsg.getStageId());
        if (chapterConfig == null) {
            return GameErrorCode.E_FOXCARD_STAGE_NOT_EXIST;
        }

        int levelNeed = chapterConfig.getTreeLimit();
        if (userData.getTreeLevel() < levelNeed) {
            return GameErrorCode.E_FOXCARD_TREE_LEVEL_NOT_ENOUGH;
        }

        if (userGameData.getStageId() == 0) {
            //首次进入生成数据
            if (userData.getGameTimes() > config.getFreeGameTimes()) {//超过免费次数,要扣道具
                Property cost = new Property(config.getStartGameItemId(), 1);
                if (!player.getModule(CurrencyModule.class).removeCurrency(cost, eLogMoneyType.FoxCard, eLogMoneyType.FoxCardStartGameCost)) {
                    return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
                }
            }
            userData.setGameTimes(userData.getGameTimes() + 1);
            UserFoxCardGameData newGameData = new FoxCardGameLogic(config, null).createNewGameData(reqMsg.getStageId(), userData.getTreeLevel());
            userGameData.copy(newGameData);

            syncUserData();

            AutoLogMgr.add(new LogFoxCardStart(userGameData.getActivityId(), userGameData.getUserId(), userGameData.getStageId()));

        } else if (userGameData.getStageId() != reqMsg.getStageId()) {
            return GameErrorCode.E_FOXCARD_ALREADY_IN_OTHER_STAGE;
        }

        FoxCardProto.FoxCardEnterStageRespMsg.Builder respMsg = FoxCardProto.FoxCardEnterStageRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setGameData(FoxCardPb.parseGameBuilder(userGameData));
        respMsg.addAllMonsters(FoxCardPb.parseMonsterTempList(new ArrayList<>(userGameData.getMonsterMap().values())));
        respMsg.setIsInBattle(userGameData.getInBattle());
        respMsg.setStageId(userGameData.getStageId());
        player.sendPacket(ClientProtocol.U_FOXCARD_ENTER_STAGE, respMsg);
        return 0;
    }

    public int enterBattle(FoxCardProto.FoxCardEnterBattleReqMsg reqMsg) {
        int ret = checkInTime(reqMsg.getActivityId());
        if (ret != 0) {
            return ret;
        }

        FoxCardConfig config = FoxCardMgr.getConfig();
        if (userGameData.getStageId() == 0) {
            return GameErrorCode.E_FOXCARD_NOT_IN_STAGE;
        }

        if (!userGameData.getWaitChooseCards().isEmpty()) {
            return GameErrorCode.E_FOXCARD_WAIT_CHOOSE_CARD;
        }

        FoxCardProto.FoxCardEnterBattleRespMsg.Builder respMsg = FoxCardProto.FoxCardEnterBattleRespMsg.newBuilder();
        respMsg.setRet(0);

        UserFoxCardGameData cloneGameData = userGameData.clone();
        FoxCardGameLogic gameLogic = new FoxCardGameLogic(config, cloneGameData);
        gameLogic.startBattle();
        userGameData.copy(cloneGameData);

        respMsg.addAllAddHandCards(FoxCardPb.parseHandCardTempList(gameLogic.getAddHandCards()));
        respMsg.setGameData(FoxCardPb.parseGameBuilder(userGameData));
        respMsg.addAllShowTemps(FoxCardPb.parseShowTempList(gameLogic.getShowInfos()));
        player.sendPacket(ClientProtocol.U_FOXCARD_ENTER_BATTLE, respMsg);

        return 0;
    }

    public int foldCard(FoxCardProto.FoxCardFoldCardReqMsg reqMsg) {
        int ret = checkInTime(reqMsg.getActivityId());
        if (ret != 0) {
            return ret;
        }
        FoxCardConfig config = FoxCardMgr.getConfig();
        if (userGameData.getStageId() == 0) {
            return GameErrorCode.E_FOXCARD_NOT_IN_STAGE;
        }
        if (!userGameData.getInBattle()) {
            return GameErrorCode.E_FOXCARD_NOT_IN_BATTLE;
        }

        if (userGameData.getDropCardTimes() <= 0) {
            return GameErrorCode.E_FOXCARD_DROP_CARD_TIMES_NOT_ENOUGH;
        }

        if (!userGameData.getWaitChooseCards().isEmpty()) {
            return GameErrorCode.E_FOXCARD_WAIT_CHOOSE_CARD;
        }

        if (userGameData.getIsShopping()) {
            return GameErrorCode.E_FOXCARD_SHOPPING_ING;
        }

        if (reqMsg.getFoldIdsCount() == 0 || reqMsg.getFoldIdsCount() > 5) {
            return GameErrorCode.E_FOXCARD_CARD_ID_EMPTY;
        }

        Set<FoxHandCard> repeatCheck = new HashSet<>();
        for (Integer cardId : reqMsg.getFoldIdsList()) {
            FoxHandCard findCard = userGameData.getHandCards().stream().filter(handCard -> handCard.getId() == cardId).findFirst().orElse(null);
            if (findCard == null) {
                return GameErrorCode.E_FOXCARD_CARD_NOT_IN_GAME;
            }
            if (repeatCheck.contains(findCard)) {
                return GameErrorCode.E_FOXCARD_CARD_ID_REPEAT;
            }
            repeatCheck.add(findCard);
        }

        LogFoxCardDrop logFoxCardDrop = new LogFoxCardDrop(userGameData.getActivityId(), userGameData.getUserId(), userGameData.getStageId(), userGameData.getRound());
        logFoxCardDrop.setDropCards(new ArrayList<>(repeatCheck));

        UserFoxCardGameData cloneGameData = userGameData.clone();
        FoxCardGameLogic gameLogic = new FoxCardGameLogic(config, cloneGameData);
        gameLogic.dropHandCards(reqMsg.getFoldIdsList());

        logFoxCardDrop.setAddCards(gameLogic.getAddHandCards());
        logFoxCardDrop.setDropCardTimes(cloneGameData.getDropCardTimes());
        logFoxCardDrop.setDropCardTimesMax(cloneGameData.getDropCardTimesMax());
        logFoxCardDrop.setGold(cloneGameData.getGold());

        userGameData.copy(cloneGameData);

        FoxCardProto.FoxCardFoldCardRespMsg.Builder respMsg = FoxCardProto.FoxCardFoldCardRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setGameData(FoxCardPb.parseGameBuilder(userGameData));
        respMsg.addAllShowTemps(FoxCardPb.parseShowTempList(gameLogic.getShowInfos()));
        respMsg.addAllAddHandCards(FoxCardPb.parseHandCardTempList(gameLogic.getAddHandCards()));
        if (userGameData.getHandCards().isEmpty() && userGameData.getRemainHandCards().isEmpty()) {
            userGameData.setStageId(0);
            userGameData.setRound(0);
            userGameData.setInBattle(false);
            userGameData.setIsShopping(false);
            respMsg.setResult(2);
            logFoxCardDrop.setResult(2);
        }
        player.sendPacket(ClientProtocol.U_FOXCARD_BATTLE_FOLD_CARD, respMsg);

        AutoLogMgr.add(logFoxCardDrop);
        return 0;
    }

    public int skipBattle(FoxCardProto.FoxCardSkipBattleReqMsg reqMsg) {
        int ret = checkInTime(reqMsg.getActivityId());
        if (ret != 0) {
            return ret;
        }

        FoxCardConfig config = FoxCardMgr.getConfig();
        if (userGameData.getStageId() == 0) {
            return GameErrorCode.E_FOXCARD_NOT_IN_STAGE;
        }
        if (userGameData.getInBattle()) {
            return GameErrorCode.E_FOXCAR_IN_BATTLE;
        }
        if (!userGameData.getWaitChooseCards().isEmpty()) {
            return GameErrorCode.E_FOXCARD_WAIT_CHOOSE_CARD;
        }

        FoxCardRoundConfig roundConfig = config.getRoundConfigMap().get(userGameData.getRound());
        if (roundConfig.getIsLimit() == 1) {//BOSS关不能跳过
            return GameErrorCode.E_FOXCARD_SKIP_BATTLE_LIMIT;
        }

        LogFoxCardSkip logFoxCardSkip = new LogFoxCardSkip(userGameData.getActivityId(), userGameData.getUserId(), userGameData.getStageId(), userGameData.getRound());
        UserFoxCardMonster monster = userGameData.getMonster(userGameData.getRound());
        if (monster.getSkipEffect() != 0) {
            logFoxCardSkip.setLabelId(monster.getSkipEffect());
        }

        UserFoxCardGameData cloneGameData = userGameData.clone();
        FoxCardGameLogic gameLogic = new FoxCardGameLogic(config, cloneGameData);
        gameLogic.skipBattle();

        logFoxCardSkip.setGold(userGameData.getGold());

        userGameData.copy(cloneGameData);

        FoxCardProto.FoxCardSkipBattleRespMsg.Builder respMsg = FoxCardProto.FoxCardSkipBattleRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setGameData(FoxCardPb.parseGameBuilder(userGameData));
        respMsg.addAllAddHandCards(FoxCardPb.parseHandCardTempList(gameLogic.getAddHandCards()));
        respMsg.addAllShowTemps(FoxCardPb.parseShowTempList(gameLogic.getShowInfos()));

        Map<Integer, Integer> passStages = new HashMap<>(userData.getPassStages());
        Integer oldPassRound = passStages.getOrDefault(userGameData.getStageId(), 0);
        int passRound = userGameData.getRound() - 1;
        if (passRound > oldPassRound) {//通关最高关卡
            passStages.put(userGameData.getStageId(), passRound);
            userData.setPassStages(passStages);
            Property reward = roundConfig.getReward(userGameData.getStageId());
            player.getModule(CurrencyModule.class).addCurrency(reward, eLogMoneyType.FoxCard, eLogMoneyType.FoxCardStagePassReward);
            respMsg.setReward(reward.toHelperString());
            logFoxCardSkip.setReward(respMsg.getReward());
        }

        player.sendPacket(ClientProtocol.U_FOXCARD_SKIP_BATTLE, respMsg);

        AutoLogMgr.add(logFoxCardSkip);
        return 0;
    }

    public int sortEffectCards(FoxCardProto.FoxCardSortEffectCardsReqMsg reqMsg) {
        int ret = checkInTime(reqMsg.getActivityId());
        if (ret != 0) {
            return ret;
        }

        FoxCardConfig config = FoxCardMgr.getConfig();
        if (userGameData.getStageId() == 0) {
            return GameErrorCode.E_FOXCARD_NOT_IN_STAGE;
        }
//        if (!userGameData.getInBattle()) {
//            return GameErrorCode.E_FOXCARD_NOT_IN_BATTLE;
//        }

        Set<Integer> repeatCheck = new HashSet<>();
        List<FoxEffectCard> effectCards = new ArrayList<>();
        for (Integer cardId : reqMsg.getCardIdsList()) {
            if (repeatCheck.contains(cardId)) {
                return GameErrorCode.E_FOXCARD_CARD_ID_REPEAT;
            }
            repeatCheck.add(cardId);
            FoxEffectCard foxEffectCard = userGameData.getEffectCards().stream().filter(card -> card.getId() == cardId).findFirst().orElse(null);
            if (foxEffectCard == null) {
                return GameErrorCode.E_FOXCARD_CARD_NOT_IN_GAME;
            }
            effectCards.add(foxEffectCard);
        }

        userGameData.setEffectCards(effectCards);
        userGameData.setUpdateOption();

        FoxCardProto.FoxCardSortEffectCardsRespMsg.Builder respMsg = FoxCardProto.FoxCardSortEffectCardsRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.addAllEffectCards(FoxCardPb.parseEffectCardTempList(effectCards));
        player.sendPacket(ClientProtocol.U_FOXCARD_BATTLE_SORT_EFFECT_CARDS, respMsg);

        return 0;
    }

    public int showCard(FoxCardProto.FoxCardShowCardReqMsg reqMsg) {
        int ret = checkInTime(reqMsg.getActivityId());
        if (ret != 0) {
            return ret;
        }

        FoxCardConfig config = FoxCardMgr.getConfig();
        if (userGameData.getStageId() == 0) {
            return GameErrorCode.E_FOXCARD_NOT_IN_STAGE;
        }
        if (!userGameData.getInBattle()) {
            return GameErrorCode.E_FOXCARD_NOT_IN_BATTLE;
        }
        if (!userGameData.getWaitChooseCards().isEmpty()) {
            return GameErrorCode.E_FOXCARD_WAIT_CHOOSE_CARD;
        }
        if (userGameData.getIsShopping()) {
            return GameErrorCode.E_FOXCARD_SHOPPING_ING;
        }

        if (userGameData.getShowCardTimes() <= 0) {
            return GameErrorCode.E_FOXCARD_SHOW_CARD_TIMES_NOT_ENOUGH;
        }

        if (reqMsg.getShowIdsCount() <= 0 || reqMsg.getShowIdsCount() > 5) {//最多打五张牌
            return GameErrorCode.E_FOXCARD_CARD_NUM_LIMIT;
        }

        Set<FoxHandCard> repeatCheck = new HashSet<>();
        for (Integer cardId : reqMsg.getShowIdsList()) {
            FoxHandCard handCard = userGameData.getHandCards().stream().filter(card -> card.getId() == cardId).findFirst().orElse(null);
            if (handCard == null) {
                return GameErrorCode.E_FOXCARD_CARD_NOT_IN_GAME;
            }
            if (repeatCheck.contains(handCard)) {
                return GameErrorCode.E_FOXCARD_CARD_ID_REPEAT;
            }
            repeatCheck.add(handCard);
        }

        LogFoxCardShowCard logFoxCardShowCard = new LogFoxCardShowCard(userGameData.getActivityId(), userGameData.getUserId(), userGameData.getStageId(), userGameData.getRound());

        UserFoxCardGameData cloneGameData = userGameData.clone();
        FoxCardGameLogic gameLogic = new FoxCardGameLogic(config, cloneGameData);
        int result = gameLogic.showHandCards(reqMsg.getShowIdsList(), userData.getEquipCards(), new ArrayList<>(userData.getUnlockCards()));

        logFoxCardShowCard.setComboId(gameLogic.getNowCombo().getComboId());
        logFoxCardShowCard.setHandCards(new ArrayList<>(repeatCheck));
        logFoxCardShowCard.setShowCardTimes(cloneGameData.getShowCardTimes());
        logFoxCardShowCard.setDropCardTimes(cloneGameData.getDropCardTimes());
        logFoxCardShowCard.setShowCardTimesMax(cloneGameData.getShowCardTimesMax());
        logFoxCardShowCard.setDropCardTimesMax(cloneGameData.getDropCardTimesMax());
        logFoxCardShowCard.setInterestGold(gameLogic.getInterestGold());
        logFoxCardShowCard.setShowTimesGold(gameLogic.getShowTimesGold());
        logFoxCardShowCard.setPassGold(gameLogic.getPassGold());
        logFoxCardShowCard.setReward("");
        logFoxCardShowCard.setGold(cloneGameData.getGold());
        logFoxCardShowCard.setDamageAmount2(cloneGameData.getDamageAmount().toString());
        logFoxCardShowCard.setDamageAdd2(gameLogic.getFinalScore().toString());
        logFoxCardShowCard.setMaxOnceDamage2(cloneGameData.getMaxOnceDamage().toString());
        logFoxCardShowCard.setBossLimit(cloneGameData.getBossLimitEffect());
        logFoxCardShowCard.setResult(result);

        userGameData.copy(cloneGameData);

        FoxCardProto.FoxCardShowCardRespMsg.Builder respMsg = FoxCardProto.FoxCardShowCardRespMsg.newBuilder();
        respMsg.setRet(0);

        Map<Integer, Integer> passStages = new HashMap<>(userData.getPassStages());
        Integer oldPassRound = passStages.getOrDefault(userGameData.getStageId(), 0);
        if (gameLogic.getPassGold() > 0 && userGameData.getRound() > oldPassRound) {//通关最高关卡
            passStages.put(userGameData.getStageId(), userGameData.getRound());
            userData.setPassStages(passStages);
            FoxCardRoundConfig roundConfig = config.getRoundConfigMap().get(userGameData.getRound());
            Property reward = roundConfig.getReward(userGameData.getStageId());
            player.getModule(CurrencyModule.class).addCurrency(reward, eLogMoneyType.FoxCard, eLogMoneyType.FoxCardStagePassReward);
            respMsg.setReward(reward.toHelperString());
            logFoxCardShowCard.setReward(respMsg.getReward());
        }

        if (result == 4) {//通关最后一关
            userGameData.setStageId(0);
            userGameData.setRound(0);
            userGameData.setUpdateOption();
        }

        respMsg.setGameData(FoxCardPb.parseGameBuilder(userGameData));
        respMsg.addAllShowTemps(FoxCardPb.parseShowTempList(gameLogic.getShowInfos()));
        respMsg.addAllAddHandCards(FoxCardPb.parseHandCardTempList(gameLogic.getAddHandCards()));
        respMsg.setRoundEffectGoldAmount(gameLogic.getEffectGoldAmount());
        respMsg.setInterestGold(gameLogic.getInterestGold());
        respMsg.setShowTimesGold(gameLogic.getShowTimesGold());
        respMsg.setPassGold(gameLogic.getPassGold());
        respMsg.setResult(result);
        if (result == 3) {
            respMsg.addAllMonsters(FoxCardPb.parseMonsterTempList(new ArrayList<>(userGameData.getMonsterMap().values())));
        }

        player.sendPacket(ClientProtocol.U_FOXCARD_BATTLE_SHOW_CARD, respMsg);

        if (userGameData.getMaxOnceDamage().compareTo(userData.getMaxScore()) > 0) {
            userData.setMaxScore(userGameData.getMaxOnceDamage());
            player.notifyListener(eGamePlayerEventType.FoxCardMaxOnceDamageRank.getValue());
        }

        syncUserData();

        AutoLogMgr.add(logFoxCardShowCard);
        return 0;
    }

    public int choosePacketCards(FoxCardProto.FoxCardChoosePacketCardsReqMsg reqMsg) {
        int ret = checkInTime(reqMsg.getActivityId());
        if (ret != 0) {
            return ret;
        }

        FoxCardConfig config = FoxCardMgr.getConfig();
        if (userGameData.getStageId() == 0) {
            return GameErrorCode.E_FOXCARD_NOT_IN_STAGE;
        }
        if (reqMsg.getChooseId() == 0 && !reqMsg.getIsSkip()) {
            return GameErrorCode.E_FOXCARD_CARD_ID_EMPTY;
        }
        if (userGameData.getWaitChooseCards().isEmpty()) {
            return GameErrorCode.E_FOXCARD_CARD_NOT_IN_GAME;
        }
        FoxCardProto.FoxCardChoosePacketCardsRespMsg.Builder respMsg = FoxCardProto.FoxCardChoosePacketCardsRespMsg.newBuilder();
        respMsg.setRet(0);

        LogFoxCardChoose logFoxCardChoose = new LogFoxCardChoose(userGameData.getActivityId(), userGameData.getUserId(), userGameData.getStageId(), userGameData.getRound());
        logFoxCardChoose.setSkip(false);
        if (reqMsg.getIsSkip()) {
            UserFoxCardGameData cloneGameData = userGameData.clone();
            FoxCardGameLogic gameLogic = new FoxCardGameLogic(config, cloneGameData);
            gameLogic.dealWaitChooseCard(reqMsg.getChooseId(), reqMsg.getEffectTargetIdList(), true);
            userGameData.copy(cloneGameData);

            respMsg.addAllShowTemps(FoxCardPb.parseShowTempList(gameLogic.getShowInfos()));

            logFoxCardChoose.setSkip(true);
            logFoxCardChoose.setGold(userGameData.getGold());
        } else {
            FoxSaleCard saleCard = userGameData.getWaitChooseCards().stream().filter(card -> card.getId() == reqMsg.getChooseId()).findFirst().orElse(null);
            if (saleCard == null) {
                return GameErrorCode.E_FOXCARD_CARD_NOT_IN_GAME;
            }

            if (saleCard.getType() == eFoxCardType.EFFECT.getValue()) {//没卡槽不能选
                if (!config.isBuffType8(saleCard.getVersionEffect())) {
                    if (userGameData.getEffectCards().size() >= userGameData.getEffectCardNumLimit()) {
                        return GameErrorCode.E_FOXCARD_CARD_NUM_LIMIT;
                    }
                }
            }

            Set<FoxHandCard> repeatCheck = new HashSet<>();

            for (Integer targetId : reqMsg.getEffectTargetIdList()) {
                FoxHandCard findCard = userGameData.getHandCards().stream().filter(handCard -> handCard.getId() == targetId).findFirst().orElse(null);
                if (findCard == null) {
                    return GameErrorCode.E_FOXCARD_CARD_NOT_IN_GAME;
                }
                if (repeatCheck.contains(findCard)) {
                    return GameErrorCode.E_FOXCARD_CARD_ID_REPEAT;
                }
                repeatCheck.add(findCard);
            }

            UserFoxCardGameData cloneGameData = userGameData.clone();
            FoxCardGameLogic gameLogic = new FoxCardGameLogic(config, cloneGameData);
            if (!gameLogic.dealWaitChooseCard(reqMsg.getChooseId(), reqMsg.getEffectTargetIdList(), false)) {
                return GameErrorCode.E_FOXCARD_CARD_USE_ERR;
            }

            userGameData.copy(cloneGameData);

            respMsg.addAllShowTemps(FoxCardPb.parseShowTempList(gameLogic.getShowInfos()));

            logFoxCardChoose.setChooseCard(saleCard);
            logFoxCardChoose.setHandCards(new ArrayList<>(repeatCheck));
            logFoxCardChoose.setGold(userGameData.getGold());
        }

        respMsg.setGameData(FoxCardPb.parseGameBuilder(userGameData));
        player.sendPacket(ClientProtocol.U_FOXCARD_CHOOSE_PACKET_CARDS, respMsg);

        AutoLogMgr.add(logFoxCardChoose);

        return 0;
    }

    public int saleCard(FoxCardProto.FoxCardSaleCardReqMsg reqMsg) {
        int ret = checkInTime(reqMsg.getActivityId());
        if (ret != 0) {
            return ret;
        }
        if (userGameData.getStageId() == 0) {
            return GameErrorCode.E_FOXCARD_NOT_IN_STAGE;
        }

        FoxCardConfig config = FoxCardMgr.getConfig();
        if (reqMsg.getCardId() == 0) {
            return GameErrorCode.E_FOXCARD_CARD_ID_EMPTY;
        }

        UserFoxCardGameData cloneGameData = userGameData.clone();
        FoxCardGameLogic gameLogic = new FoxCardGameLogic(config, cloneGameData);
        FoxBaseCard foxBaseCard = gameLogic.saleCard(reqMsg.getCardId());
        if (foxBaseCard == null) {
            return GameErrorCode.E_FOXCARD_CARD_NOT_IN_GAME;
        }

        userGameData.copy(cloneGameData);

        AutoLogMgr.add(new LogFoxCardSale(userGameData.getActivityId(), userGameData.getUserId(), userGameData.getStageId(), userGameData.getRound(), foxBaseCard, cloneGameData.getGold()));


        FoxCardProto.FoxCardSaleCardRespMsg.Builder respMsg = FoxCardProto.FoxCardSaleCardRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setCardId(foxBaseCard.getId());
        respMsg.addAllShowTemps(FoxCardPb.parseShowTempList(gameLogic.getShowInfos()));
        respMsg.setGameData(FoxCardPb.parseGameBuilder(userGameData));
        player.sendPacket(ClientProtocol.U_FOXCARD_BATTLE_SALE_CARD, respMsg);
        return 0;
    }

    public int shoppingBuy(FoxCardProto.FoxCardShoppingBuyReqMsg reqMsg) {
        int ret = checkInTime(reqMsg.getActivityId());
        if (ret != 0) {
            return ret;
        }

        FoxCardConfig config = FoxCardMgr.getConfig();
        if (userGameData.getStageId() == 0) {
            return GameErrorCode.E_FOXCARD_NOT_IN_STAGE;
        }

        if (!userGameData.getIsShopping()) {
            return GameErrorCode.E_FOXCARD_SHOPPING_ING;
        }

        if (!userGameData.getWaitChooseCards().isEmpty()) {
            return GameErrorCode.E_FOXCARD_WAIT_CHOOSE_CARD;
        }

        LogFoxCardBuy logFoxCardBuy = new LogFoxCardBuy(userGameData.getActivityId(), userGameData.getUserId(), userGameData.getStageId(), userGameData.getRound());
        logFoxCardBuy.setUse(reqMsg.getIsUse());
        logFoxCardBuy.setBuyPos(reqMsg.getType());

        FoxCardProto.FoxCardShoppingBuyRespMsg.Builder respMsg = FoxCardProto.FoxCardShoppingBuyRespMsg.newBuilder();
        respMsg.setRet(0);

        if (reqMsg.getType() == 1) {//买位置1 可刷新的卡
            FoxSaleCard foxSaleCard = userGameData.getShop().getSaleCards().stream().filter(card -> card.getId() == reqMsg.getBuyId()).findFirst().orElse(null);
            if (foxSaleCard == null) {
                return GameErrorCode.E_FOXCARD_CARD_NOT_IN_GAME;
            }
            if (foxSaleCard.getType() == eFoxCardType.EFFECT.getValue()) {
                if (!config.isBuffType8(foxSaleCard.getVersionEffect()) && userGameData.getEffectCards().size() >= userGameData.getEffectCardNumLimit()) {
                    return GameErrorCode.E_FOXCARD_CARD_NUM_LIMIT;
                }
            } else if (foxSaleCard.getType() == eFoxCardType.MAGIC_WEAPON.getValue()) {
                //如果没有马上使用,要判断是否有卡槽
                if (!reqMsg.getIsUse()) {
                    if (!config.isBuffType8(foxSaleCard.getVersionEffect()) && userGameData.getConsumeCards().size() >= userGameData.getConsumeCardNumLimit()) {
                        return GameErrorCode.E_FOXCARD_CARD_NUM_LIMIT;
                    }
                }

            } else if (foxSaleCard.getType() == eFoxCardType.SPELL.getValue()) {
                //如果没有马上使用,要判断是否有卡槽
                if (!reqMsg.getIsUse()) {
                    if (!config.isBuffType8(foxSaleCard.getVersionEffect()) && userGameData.getConsumeCards().size() >= userGameData.getConsumeCardNumLimit()) {
                        return GameErrorCode.E_FOXCARD_CARD_NUM_LIMIT;
                    }
                }
            } else if (foxSaleCard.getType() == eFoxCardType.SORCERY.getValue()) {
                //如果没有马上使用,要判断是否有卡槽
                if (!reqMsg.getIsUse()) {
                    if (!config.isBuffType8(foxSaleCard.getVersionEffect()) && userGameData.getConsumeCards().size() >= userGameData.getConsumeCardNumLimit()) {
                        return GameErrorCode.E_FOXCARD_CARD_NUM_LIMIT;
                    }
                }
            }
            logFoxCardBuy.setBuyCard(foxSaleCard.clone());
        } else if (reqMsg.getType() == 2) {//卡包
            FoxCardPack foxCardPack = userGameData.getShop().getCardPacks().stream().filter(cardPack -> cardPack.getCardPackId() == reqMsg.getBuyId()).findFirst().orElse(null);
            if (foxCardPack == null) {
                return GameErrorCode.E_FOXCARD_CARD_NOT_IN_GAME;
            }
            logFoxCardBuy.setCardPackId(foxCardPack.getCardPackId());
        } else if (reqMsg.getType() == 3) {//优惠券
            if (userGameData.getShop().getCoupon() == null) {
                return GameErrorCode.E_FOXCARD_CARD_NOT_IN_GAME;
            }
            logFoxCardBuy.setBuyCard(userGameData.getShop().getCoupon().clone());
        } else {
            return GameErrorCode.E_ERROR_PARAMETER;
        }



        UserFoxCardGameData cloneGameData = userGameData.clone();
        FoxCardGameLogic gameLogic = new FoxCardGameLogic(config, cloneGameData);

        int price = gameLogic.calcBuyPrice(reqMsg.getBuyId(), reqMsg.getType());
        if (cloneGameData.getGold() < price) {
            return GameErrorCode.E_FOXCARD_GOLD_NOT_ENOUGH;
        }

        if (!gameLogic.buyCard(reqMsg.getBuyId(), reqMsg.getType(), reqMsg.getIsUse())) {
            return GameErrorCode.E_FOXCARD_CARD_USE_ERR;
        }

        logFoxCardBuy.setPayGold(price);
        logFoxCardBuy.setGold(cloneGameData.getGold());

        userGameData.copy(cloneGameData);

        respMsg.setGameData(FoxCardPb.parseGameBuilder(userGameData));
        respMsg.addAllAddHandCards(FoxCardPb.parseHandCardTempList(gameLogic.getAddHandCards()));
        respMsg.addAllShowTemps(FoxCardPb.parseShowTempList(gameLogic.getShowInfos()));
        player.sendPacket(ClientProtocol.U_FOXCARD_SHOPPING_BUY, respMsg);

        AutoLogMgr.add(logFoxCardBuy);

        return 0;
    }

    public int shoppingRefresh(FoxCardProto.FoxCardShoppingRefreshReqMsg reqMsg) {
        int ret = checkInTime(reqMsg.getActivityId());
        if (ret != 0) {
            return ret;
        }

        FoxCardConfig config = FoxCardMgr.getConfig();
        if (userGameData.getStageId() == 0) {
            return GameErrorCode.E_FOXCARD_NOT_IN_STAGE;
        }

        if (!userGameData.getIsShopping()) {
            return GameErrorCode.E_FOXCARD_SHOPPING_ING;
        }

        if (!userGameData.getWaitChooseCards().isEmpty()) {
            return GameErrorCode.E_FOXCARD_WAIT_CHOOSE_CARD;
        }

        if (userGameData.getShop().getFreeTimes() == 0) {
            if (userGameData.getGold() < userGameData.getShop().getRefreshPrice()) {
                return GameErrorCode.E_FOXCARD_GOLD_NOT_ENOUGH;
            }
        }

        LogFoxCardRefresh logFoxCardRefresh = new LogFoxCardRefresh(userGameData.getActivityId(), userGameData.getUserId(), userGameData.getStageId(), userGameData.getRound());
        logFoxCardRefresh.setSaleCardsBefore(new ArrayList<>(userGameData.getShop().getSaleCards()));
        logFoxCardRefresh.setRefreshAmount(userGameData.getShop().getRefreshAmount());
        logFoxCardRefresh.setRefreshPrice(userGameData.getShop().getRefreshPrice());
        logFoxCardRefresh.setFreeTimes(userGameData.getShop().getFreeTimes());

        UserFoxCardGameData cloneGameData = userGameData.clone();
        FoxCardGameLogic gameLogic = new FoxCardGameLogic(config, cloneGameData);
        gameLogic.refreshShop();

        logFoxCardRefresh.setSaleCardsAfter(new ArrayList<>(cloneGameData.getShop().getSaleCards()));
        logFoxCardRefresh.setGold(cloneGameData.getGold());

        userGameData.copy(cloneGameData);

        FoxCardProto.FoxCardShoppingRefreshRespMsg.Builder respMsg = FoxCardProto.FoxCardShoppingRefreshRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setGameData(FoxCardPb.parseGameBuilder(userGameData));
        respMsg.addAllShowTemps(FoxCardPb.parseShowTempList(gameLogic.getShowInfos()));
        player.sendPacket(ClientProtocol.U_FOXCARD_SHOPPING_REFRESH, respMsg);

        AutoLogMgr.add(logFoxCardRefresh);

        return 0;
    }

    public int useConsumeCard(FoxCardProto.FoxCardUseConsumeCardReqMsg reqMsg) {
        int ret = checkInTime(reqMsg.getActivityId());
        if (ret != 0) {
            return ret;
        }

        FoxCardConfig config = FoxCardMgr.getConfig();
        if (userGameData.getStageId() == 0) {
            return GameErrorCode.E_FOXCARD_NOT_IN_STAGE;
        }

//        if (!userGameData.getWaitChooseCards().isEmpty()) {
//            return GameErrorCode.E_FOXCARD_WAIT_CHOOSE_CARD;
//        }

        FoxConsumeCard foxConsumeCard = userGameData.getConsumeCards().stream().filter(card -> card.getId() == reqMsg.getCardId()).findFirst().orElse(null);
        if (foxConsumeCard == null) {
            return GameErrorCode.E_FOXCARD_CARD_NOT_IN_GAME;
        }


        UserFoxCardGameData cloneGameData = userGameData.clone();
        FoxCardGameLogic gameLogic = new FoxCardGameLogic(config, cloneGameData);
        if (!gameLogic.useConsumeCard(reqMsg.getCardId(), reqMsg.getTargetIdList())) {
            return GameErrorCode.E_FOXCARD_CARD_USE_ERR;
        }

        LogFoxCardUse logFoxCardUse = new LogFoxCardUse(userGameData.getActivityId(), userGameData.getUserId(), userGameData.getStageId(), userGameData.getRound(), cloneGameData.getGold(), foxConsumeCard);
        if (!reqMsg.getTargetIdList().isEmpty()) {
            List<FoxHandCard> logTartCards = new ArrayList<>();
            for (Integer handCardId : reqMsg.getTargetIdList()) {
                FoxHandCard foxHandCard = cloneGameData.getHandCards().stream().filter(handCard -> handCard.getId() == handCardId).findFirst().orElse(null);
                logTartCards.add(foxHandCard);
            }
            logFoxCardUse.setTargetHandCards(logTartCards);
        }

        userGameData.copy(cloneGameData);

        FoxCardProto.FoxCardUseConsumeCardRespMsg.Builder respMsg = FoxCardProto.FoxCardUseConsumeCardRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setGameData(FoxCardPb.parseGameBuilder(userGameData));
        respMsg.addAllShowTemps(FoxCardPb.parseShowTempList(gameLogic.getShowInfos()));
        respMsg.addAllAddHandCards(FoxCardPb.parseHandCardTempList(gameLogic.getAddHandCards()));

        if (userGameData.getHandCards().isEmpty() && userGameData.getRemainHandCards().isEmpty()) {
            userGameData.setStageId(0);
            userGameData.setRound(0);
            userGameData.setInBattle(false);
            userGameData.setIsShopping(false);
            respMsg.setResult(2);
            logFoxCardUse.setResult(2);
        }

        player.sendPacket(ClientProtocol.U_FOXCARD_BATTLE_USE_CONSUME_CARD, respMsg);

        AutoLogMgr.add(logFoxCardUse);

        return 0;
    }

    public int endShopping(FoxCardProto.FoxCardEndShoppingReqMsg reqMsg) {
        int ret = checkInTime(reqMsg.getActivityId());
        if (ret != 0) {
            return ret;
        }

        FoxCardConfig config = FoxCardMgr.getConfig();
        if (userGameData.getStageId() == 0) {
            return GameErrorCode.E_FOXCARD_NOT_IN_STAGE;
        }

        if (!userGameData.getIsShopping()) {
            return GameErrorCode.E_FOXCARD_SHOPPING_ING;
        }

        if (!userGameData.getWaitChooseCards().isEmpty()) {
            return GameErrorCode.E_FOXCARD_WAIT_CHOOSE_CARD;
        }

        UserFoxCardGameData cloneGameData = userGameData.clone();
        FoxCardGameLogic gameLogic = new FoxCardGameLogic(config, cloneGameData);
        gameLogic.endShopping();

        userGameData.copy(cloneGameData);

        FoxCardProto.FoxCardEndShoppingRespMsg.Builder respMsg = FoxCardProto.FoxCardEndShoppingRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setGameData(FoxCardPb.parseGameBuilder(userGameData));
        respMsg.addAllShowTemps(FoxCardPb.parseShowTempList(gameLogic.getShowInfos()));
        player.sendPacket(ClientProtocol.U_FOXCARD_END_SHOPPING, respMsg);

        return 0;
    }

    public int getShowCardCombo(FoxCardProto.FoxCardGetShowCardComboReqMsg reqMsg) {
        int ret = checkInTime(reqMsg.getActivityId());
        if (ret != 0) {
            return ret;
        }
        if (userGameData.getStageId() == 0) {
            return GameErrorCode.E_FOXCARD_NOT_IN_STAGE;
        }
        if (!userGameData.getInBattle()) {
            return GameErrorCode.E_FOXCARD_NOT_IN_BATTLE;
        }

        Set<FoxHandCard> repeatCheck = new HashSet<>();
        for (Integer cardId : reqMsg.getCardIdsList()) {
            FoxHandCard handCard = userGameData.getHandCards().stream().filter(card -> card.getId() == cardId).findFirst().orElse(null);
            if (handCard == null) {
                return GameErrorCode.E_FOXCARD_CARD_NOT_IN_GAME;
            }
            if (repeatCheck.contains(handCard)) {
                return GameErrorCode.E_FOXCARD_CARD_ID_REPEAT;
            }
            repeatCheck.add(handCard);

        }

        FoxCardConfig config = FoxCardMgr.getConfig();
        FoxCardCombo foxCardCombo = new FoxCardGameLogic(config, userGameData).calcShowCardCombo(new ArrayList<>(repeatCheck));
        FoxCardProto.FoxCardGetShowCardComboRespMsg.Builder respMsg = FoxCardProto.FoxCardGetShowCardComboRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setComboId(foxCardCombo.getComboId());
        respMsg.addAllComboCards(FoxCardPb.parseHandCardTempList(foxCardCombo.getHandCards()));
        respMsg.setLevel(foxCardCombo.getLevel());
        player.sendPacket(ClientProtocol.U_FOXCARD_GET_SHOW_CARD_COMBO, respMsg);
        return 0;
    }

    public int exitGame(int activityId) {
        int ret = checkInTime(activityId);
        if (ret != 0) {
            return ret;
        }

        AutoLogMgr.add(new LogFoxCardExit(userGameData.getActivityId(), userGameData.getUserId(), userGameData.getStageId(), userGameData.getRound()));

        userGameData.setStageId(0);
        userGameData.setRound(0);
        userGameData.setInBattle(false);
        userGameData.setIsShopping(false);

        FoxCardProto.FoxCardExitGameRespMsg.Builder respMsg = FoxCardProto.FoxCardExitGameRespMsg.newBuilder();
        respMsg.setRet(0);
        player.sendPacket(ClientProtocol.U_FOXCARD_EXIT_GAME, respMsg);

        syncUserData();
        return 0;
    }

    public UserFoxCardData getUserData() {
        return userData;
    }

    public UserFoxCardGameData getUserGameData() {
        return userGameData;
    }

    public int treeLevelUp(int activityId) {
        int ret = checkInTime(activityId);
        if (ret > 0) {
            return ret;
        }

        FoxCardConfig config = FoxCardMgr.getConfig();
        int oldLevel = userData.getTreeLevel();
        int newLevel = config.calcTreeLevel(userData.getTreeExp());
        if (oldLevel == newLevel) {
            return GameErrorCode.E_FOXCARD_TREE_EXP_NOT_ENOUGH;
        }

        userData.setTreeLevel(newLevel);
        AutoLogMgr.add(new LogFoxCardTreeLvUp(userData.getActivityId(), userData.getUserId(), newLevel));

        FoxCardProto.FoxCardTreeLvUpRespMsg.Builder respMsg = FoxCardProto.FoxCardTreeLvUpRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setLevel(newLevel);
        player.sendPacket(ClientProtocol.U_FOXCARD_TREE_LV_UP, respMsg);
        syncUserData();
        return 0;
    }

    public int guideUpdate(int activityId, String guide, boolean completeGuide) {
        int ret = checkInTime(activityId);
        if (ret > 0) {
            return ret;
        }

        userData.setGuide(guide);
        FoxCardProto.FoxCardGuideUpdateRespMsg.Builder respMsg = FoxCardProto.FoxCardGuideUpdateRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setGuide(guide);

        //判断是否完成所有引导，玩家维度上记录下来，之后的活动就可以根据该记录判断是否可以跳过引导
        if (completeGuide) {
            FoxCardConfig config = FoxCardMgr.getConfig();
            if (config != null && config.getActivityInfo() != null) {
                player.getModule(UserActModule.class).addCompleteGuideActivityType(config.getActivityInfo().getType(), config.getActivityInfo().getChildType());
            }
        }

        player.sendPacket(ClientProtocol.U_FOXCARD_GUIDE_UPDATE, respMsg);

        syncUserData();

        return 0;
    }

    public void resetOneDay(boolean isLogin) {
        if (userData == null) {
            return;
        }

        long currentTime = DateHelper.getCurrentTime();
        if (DateHelper.isSameDay(userData.getLastGameTime() / 1000, currentTime / 1000)) {
            return;
        }
        userData.setLastGameTime(currentTime);
        userData.setGameTimes(0);
        if (!isLogin) {
            syncUserData();
        }
    }

    public int fastPassStage(int activityId, int stageId) {
        int ret = checkInTime(activityId);
        if (ret > 0) {
            return ret;
        }

        FoxCardConfig config = FoxCardMgr.getConfig();

        if (userData.getGameTimes() > config.getFreeGameTimes()) {//超过免费次数,要扣道具
            Property cost = new Property(config.getStartGameItemId(), 1);
            if (!player.getModule(CurrencyModule.class).removeCurrency(cost, eLogMoneyType.FoxCard, eLogMoneyType.FoxCardStartGameCost)) {
                return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
            }
        }
        userData.setGameTimes(userData.getGameTimes() + 1);

        FoxCardChapterConfig chapterConfig = config.getChapterConfigMap().get(stageId);
        if (chapterConfig == null) {
            return GameErrorCode.E_ERROR_PARAMETER;
        }

        FoxCardTreeLevelConfig treeLevelConfig = config.getTreeLevelConfig(userData.getTreeLevel());
        if (treeLevelConfig == null) {
            return GameErrorCode.E_FOXCARD_LOTTERY_CONFIG_ERR;
        }

        if (!treeLevelConfig.getFastPassIds().contains(stageId)) {
            return GameErrorCode.E_ERROR_PARAMETER;
        }

        Map<Integer, Integer> passStages = new HashMap<>(userData.getPassStages());
        Integer oldPassRound = passStages.getOrDefault(stageId, 0);
        if (oldPassRound >= config.getFOX_ENDLESS_MODE_MISSION()) {
            return GameErrorCode.E_FOXCARD_STAGE_ALREADY_PASS;
        }

        Property totalReward = new Property();
        for (int i = oldPassRound + 1; i <= config.getFOX_ENDLESS_MODE_MISSION(); i++) {
            FoxCardRoundConfig roundConfig = config.getRoundConfigMap().get(i);
            Property reward = roundConfig.getReward(stageId);
            totalReward.addProperty(reward);
        }

        passStages.put(stageId, config.getFOX_ENDLESS_MODE_MISSION());
        userData.setPassStages(passStages);
        player.getModule(CurrencyModule.class).addCurrency(totalReward, eLogMoneyType.FoxCard, eLogMoneyType.FoxCardStagePassReward);

        FoxCardProto.FoxCardFastPassRespMsg.Builder respMsg = FoxCardProto.FoxCardFastPassRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setStageId(stageId);
        respMsg.setReward(totalReward.toHelperString());
        player.sendPacket(ClientProtocol.U_FOXCARD_FAST_PASS_STAGE, respMsg);

        AutoLogMgr.add(new LogFoxCardFastPass(userData.getActivityId(), userData.getUserId(), stageId, oldPassRound, config.getFOX_ENDLESS_MODE_MISSION(), respMsg.getReward()));

        syncUserData();
        return 0;
    }

    public int randomNextGuaranteeNum(int activityId) {
        int ret = checkInTime(activityId);
        if (ret > 0) {
            return ret;
        }

        if (userData.getGuaranteeAmount() != -1) {
            return GameErrorCode.E_ERROR_PARAMETER;
        }

        FoxCardConfig config = FoxCardMgr.getConfig();

        //先算玩家当前的每点体力对应的积分
        BigDecimal perPowerScore = BigDecimal.valueOf(userData.getTreeScore()).divide(BigDecimal.valueOf(userData.getPowerAmount()), 8, BigDecimal.ROUND_UP);
        //判断是否要进行动态权重计算
        Map<Integer, Integer> randomPool = config.getRecallLotteryRandomPool();
        Map<String, ActivityConfig> configMap = ActivityMgr.getActivityConfigMap(config.getActivityId());
        ActivityConfig randomPoolConfig = configMap.get("FOX_RECALL_POWER_GUARANTEES_NEW");//代码更新后,才说要加这种配置,只能这么写
        if (randomPoolConfig != null) {
            //0,2;20|3;30|4;50|5;100|6;120|7;140|8;160|9;180|10;200#1000,2;20|3;30|4;50|5;100|6;120|7;140|8;160|9;180|10;200
            for (String s : randomPoolConfig.getValue().split("#")) {
                List<String> list = StringUtils.stringToStringList(s, ",");
                int minPower = Integer.valueOf(list.get(0));
                Map<Integer, Integer> configRandomPool = new HashMap<>();
                for (String s1 : list.get(1).split("\\|")) {
                    List<Integer> list1 = StringUtils.stringToIntegerList(s1, ";");
                    configRandomPool.put(list1.get(0), list1.get(1));
                }
                if (userData.getPowerAmount() >= minPower) {
                    randomPool = configRandomPool;
                }
            }
        }

        if (perPowerScore.compareTo(config.getComparePowerScore()) < 0) {
            /**
             * y=a1*x^3+a2*x^2+a3*x+a4
             * 参数均为千分比，即除以1000为实际值
             *
             * x=玩家当前积分/（当前消耗体力*平均单体力积分）
             *
             * 得出值均为权重值而非概率值，因为会存在0.001的误差可能性存在导致总和概率大于1或小于1
             *
             * 除2.3.4.5其余权重为0
             */
            BigDecimal x = perPowerScore.divide(BigDecimal.valueOf(config.getRecallCompareParams().get(0)), 8, BigDecimal.ROUND_DOWN);
            Map<Integer, Integer> balanceRandomPool = new HashMap<>();
            for (Map.Entry<Integer, Integer> entry : randomPool.entrySet()) {
                Integer num = entry.getKey();
                List<Integer> list = config.getRecallBalanceParamsMap().get(num);
                if (list != null) {
                    int calcWeight = BigDecimal.valueOf(list.get(0)).multiply(BigDecimal.valueOf(Math.pow(x.doubleValue(), 3))).
                            add(BigDecimal.valueOf(list.get(1)).multiply(BigDecimal.valueOf(Math.pow(x.doubleValue(), 2)))).
                            add(BigDecimal.valueOf(list.get(2)).multiply(x)).
                            add(BigDecimal.valueOf(list.get(3))).intValue();
                    balanceRandomPool.put(num, calcWeight);
                }
            }
            randomPool = balanceRandomPool;
        }

        int nextNum = config.getRandomHelper().getRandomKeyByWeightEx(randomPool);

        userData.setGuaranteeAmount(nextNum);
        //金色保底
        if (userData.getGoldenGuaranteeAmount()+1 >= config.getGoldenGuaranteeNum()) {
            userData.setGoldenGuarantee(true);
            userData.setGoldenGuaranteeAmount(0);
        }else {
            int randomValue = config.getRandomHelper().next(1000);
            if (randomValue < config.getGoldenRecallParams().get(0)) {
                userData.setGoldenGuarantee(true);
                userData.setGoldenGuaranteeAmount(0);
            }else {
                userData.setGoldenGuarantee(false);
                userData.setGoldenGuaranteeAmount(userData.getGoldenGuaranteeAmount() + 1);
            }
        }


        FoxCardProto.FoxCardRandomNextGuaranteeNumRespMsg.Builder resp = FoxCardProto.FoxCardRandomNextGuaranteeNumRespMsg.newBuilder();
        resp.setRet(0);
        resp.setNum(userData.getGuaranteeAmount());
        player.sendPacket(ClientProtocol.U_FOXCARD_RANDOM_NEXT_GUARANTEE_NUM, resp);

        AutoLogMgr.add(new LogFoxCardRandomNextGuarantee(userData.getActivityId(), userData.getUserId(), userData.getLotteryRound(), userData.getGuaranteeAmount()));

        syncUserData();
        return 0;
    }
}
